#include "utils.h"
#include <QDateTime>
#include <QDebug>
#include <QDir>
#include <QFormLayout>
#include <QJsonDocument>
#include <QPainter>
#include <QPainterPath>
#include <QProcess>
#include <QScreen>
#include <QStandardPaths>
#include <QStorageInfo>
#include <QWindow>

#ifdef Q_OS_WIN
#include <Windows.h>
#endif

namespace utils {

qreal devicePixelRatio(QWindow* window)
{
    qreal ratio = 1.0;
    if (window) {
        if (QScreen* s = window->screen()) {
            ratio = s->devicePixelRatio();
        }
    }
    return ratio;
}

bool isHD(QWidget* widget)
{
    Q_ASSERT(widget);
    return (devicePixelRatio(widget->window()->windowHandle()) > 1.0);
}

QMessageBox::StandardButton msgBox(QWidget* parent, const QString& title, const QString& text,
                                   QMessageBox::StandardButtons buttons,
                                   QMessageBox::StandardButton defaultButton,
                                   QMessageBox::Icon icon)
{
    QMessageBox mb(icon, title, text, buttons, parent);
    mb.setObjectName("normal");
    mb.setDefaultButton(defaultButton);
    mb.setStyleSheet("QLabel#qt_msgbox_label{min-width:360px;margin-bottom:20px;font-size:12px;"
                     "text-align:left;"
                     "} QPushButton{min-width:60px;}");
    // qt_msgboxex_icon_label
    return QMessageBox::StandardButton(mb.exec());
}

QSize labelPreferredSize(QFormLayout* layout)
{
    QSize sz(14, 14);
    Q_ASSERT(layout);
    for (int i = layout->rowCount() - 1; i > -1; --i) {
        if (layout->isRowVisible(i)) {
            if (auto p = layout->itemAt(i, QFormLayout::LabelRole)) {
                const auto r = p->geometry();
                if (r.width() > sz.width()) {
                    sz.setWidth(r.width());
                    sz.setHeight(r.height());
                }
            }
        }
    }
    return sz;
}

QPixmap circlePixmap(const QString& path, const QSize& size)
{
    QPixmap pixmap(path);
    if (pixmap.width() > 0) {
        QPixmap circle = pixmap.scaled(size, Qt::KeepAspectRatio, Qt::SmoothTransformation);
        int w = size.width();
        int h = w;
        int x = (size.width() - circle.width()) / 2;
        int y = (size.height() - circle.height()) / 2;
        QPixmap pm(w, h);
        pm.fill(Qt::transparent);
        QRect r(0, 0, w, h);
        QPainter painter(&pm);
        painter.setRenderHints(QPainter::SmoothPixmapTransform | QPainter::Antialiasing);
        painter.setPen(Qt::black);
        painter.setBrush(Qt::black);
        painter.drawEllipse(r);
        QPainterPath clip_path;
        clip_path.addEllipse(r);
        painter.setClipPath(clip_path);
        painter.drawPixmap(QPoint(x, y), circle);
        painter.end();
        return pm;
    }
    return pixmap;
}

QPixmap uniformPixmap(const QString& path, const QSize& size)
{
    QPixmap pixmap(path);
    if (pixmap.width() > 0 && size.height() > 0
        && (pixmap.width() != size.width() || pixmap.height() != size.height())) {
        qreal ratio = qreal(size.width()) / qreal(size.height());
        if (ratio > 1.0) {
            int w = pixmap.width();
            int h = std::ceil(qreal(w) / ratio);
            int y = (pixmap.height() - h) / 2;
            return pixmap.copy(0, y, w, h);
        }
    }
    return pixmap;
}

QString wrapToolTip(const QString& text, int width)
{
    return QString("<p style='white-space: pre-wrap; width: %1px;'>%2</p>").arg(width).arg(text);
}

void showFileInFolder(const QString& path)
{
#ifdef Q_OS_WIN // Code for Windows
    QProcess::startDetached("explorer.exe", { "/select,", QDir::toNativeSeparators(path) });
#elif defined(Q_OS_MAC) // Code for Mac
    QProcess::execute(
            "/usr/bin/osascript",
            { "-e", "tell application \"Finder\" to reveal POSIX file \"" + path + "\"" });
    QProcess::execute("/usr/bin/osascript", { "-e", "tell application \"Finder\" to activate" });
#endif
}

QString clockDisplayString(qint64 ms)
{
    if (ms < 0) {
        return QString("00:00:00");
    } else {
        int hour = int(ms / (3600 * 1000));
        int minute = int((ms - hour * 3600 * 1000) / (60 * 1000));
        int sec = int((ms - hour * 3600 * 1000 - minute * 60 * 1000) / 1000);
        if (hour > 0) {
            return QString("%1:%2:%3")
                    .arg(hour, 2, 10, QChar('0'))
                    .arg(minute, 2, 10, QChar('0'))
                    .arg(sec, 2, 10, QChar('0'));
        } else {
            return QString("%1:%2").arg(minute, 2, 10, QChar('0')).arg(sec, 2, 10, QChar('0'));
        }
    }
}

qint64 getTotalSystemMemory()
{
    // 获取系统总内存大小，单位为字节
#if defined(Q_OS_LINUX)
    // Linux 系统下读取 /proc/meminfo 文件获取总内存
    QFile file("/proc/meminfo");
    if (file.open(QIODevice::ReadOnly)) {
        QByteArray line = file.readLine(); // 读取第一行，包含总内存信息
        qint64 memTotal =
                line.split(' ').last().replace("kB", "").toLongLong() * 1024; // 转换为字节
        return memTotal;
    }
#elif defined(Q_OS_WIN)
    // Windows 系统下使用 GlobalMemoryStatusEx 函数
    MEMORYSTATUSEX memoryStatus;
    memoryStatus.dwLength = sizeof(memoryStatus);
    if (GlobalMemoryStatusEx(&memoryStatus)) {
        return static_cast<qint64>(memoryStatus.ullTotalPhys);
    }
#endif
    return -1; // 如果无法确定内存大小，则返回-1
}

QString createDirectoryInNonSystemDrive(const QString& dir_name)
{
    if (dir_name.isEmpty()) {
        qDebug() << "Directory name is empty";
        return QString();
    }

    // 获取所有挂载点
    const QList<QStorageInfo> storageList = QStorageInfo::mountedVolumes();
    if (storageList.isEmpty()) {
        qDebug() << "No mounted volumes found";
        return QString();
    }

    // 系统盘路径
    QString systemRoot = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);
    if (systemRoot.isEmpty()) {
        systemRoot = QDir::rootPath(); // fallback to root path
    }

    // 提取系统盘路径的前缀（Windows 下如 "C:/"，Linux/macOS 下为 "/"）
    QString systemRootPrefix;
    if (systemRoot.startsWith("/")) {
        systemRootPrefix = "/";
    } else {
        systemRootPrefix = systemRoot.left(2); // Windows C:/ -> "C:"
    }

    qDebug() << "System root prefix:" << systemRootPrefix;

    // 查找可用空间最大的非系统盘
    QString targetPath;
    qint64 maxFreeSpace = -1;

    for (const QStorageInfo& storage : storageList) {
        const QString deviceRoot = storage.rootPath();
        if (deviceRoot.isEmpty()) {
            continue; // 跳过无效的挂载点
        }

        qint64 freeSpace = storage.bytesAvailable();
        if (freeSpace < 0) {
            continue; // 跳过无法获取空间信息的磁盘
        }

        // 如果只有一个磁盘，或者当前磁盘不是系统盘
        if (storageList.size() == 1
            || (deviceRoot != "/" && deviceRoot.left(2) != systemRootPrefix)) {
            if (freeSpace > maxFreeSpace) {
                maxFreeSpace = freeSpace;
                targetPath = deviceRoot;
            }
        }
    }

    // 如果没有找到合适的磁盘
    if (targetPath.isEmpty()) {
        qDebug() << "No suitable drive found.";
        return QString();
    }

    // 构造最终目录路径
    const QDir dir(targetPath);
    const QString fullPath = dir.filePath(dir_name);

    // 创建目录
    if (!QDir().exists(fullPath)) {
        if (QDir().mkpath(fullPath)) {
            qDebug() << "Successfully created directory at:" << fullPath;
        } else {
            qDebug() << "Failed to create directory at:" << fullPath;
            return QString();
        }
    } else {
        qDebug() << "Directory already exists at:" << fullPath;
    }

    return fullPath;
}

bool isSystemDrive(const QString& dirPath)
{
    // 获取目标目录的绝对路径
    const QFileInfo dirInfo(dirPath);
    if (!dirInfo.isDir())
        return false; // 确保给定路径是一个目录

    // 获取用户的home路径
    const QString homePath = QStandardPaths::writableLocation(QStandardPaths::HomeLocation);

#ifdef Q_OS_WIN
    // 在Windows上，获取包含home目录的驱动器
    const QString systemDrive = homePath.left(2); // 提取类似 "C:" 的部分
#else
    // 在Unix-like系统上，home目录通常不在根目录下，因此我们检查根目录 '/'
    const QString systemDrive = "/";
#endif

    // 比较目标目录所在的驱动器或根目录与系统盘
    if (dirInfo.absolutePath().startsWith(systemDrive, Qt::CaseInsensitive)) {
        return true;
    }

    return false;
}

} // namespace utils
